﻿using System.Data.Common;
using System.Xml.XPath;

namespace Songhay.Data
{
    using Songhay.Xml;

    /// <summary>
    /// Command input
    /// for <see cref="Songhay.Data.ICommandHandler"/>.
    /// </summary>
    public class DataCommandInput<MessageType> : DataCommandInput
    {

        /// <summary>
        /// Default constructor.
        /// </summary>
        public DataCommandInput() : base() { }

        /// <summary>
        /// Constructs with the specified command name
        /// and <see cref="System.Data.Common.DbConnection"/>.
        /// </summary>
        /// <param name="commandName">the command name</param>
        /// <param name="dataConnection">the <see cref="System.Data.Common.DbConnection"/></param>
        public DataCommandInput(string commandName, DbConnection dataConnection)
            : base(commandName, dataConnection) { }

        /// <summary>
        /// Constructs with the specified command name
        /// and <see cref="System.Data.Common.DbConnection"/>.
        /// </summary>
        /// <param name="message">the strongly-typed message</param>
        /// <param name="commandName">the command name</param>
        /// <param name="dataConnection">the <see cref="System.Data.Common.DbConnection"/></param>
        public DataCommandInput(MessageType message, string commandName, DbConnection dataConnection)
            : base(commandName, dataConnection)
        {
            this._message = message;
        }

        /// <summary>
        /// The strongly typed message of this input.
        /// </summary>
        public MessageType Message
        {
            get { return this._message; }
            set { this._message = value; }
        }

        /// <summary>
        /// Attempts to get a unique identifier
        /// from <see cref="Songhay.Data.DataCommandInput&lt;MessageType&gt;.Message"/>.
        /// </summary>
        /// <returns>Returns a unique identifier.</returns>
        /// <remarks>Currently this method only supports <c>MessageType as String</c>.</remarks>
        public string GetUniqueIdentifier()
        {
            if(this.Message == null) return null;

            if(typeof(MessageType).Equals(typeof(string)))
            {
                return (XmlUtility.IsXml(this.Message.ToString())) ? null : this.Message.ToString();
            }//TODO: support more MessageType types.
            else
            {
                return null;
            }
        }

        MessageType _message;
    }

    /// <summary>
    /// Command input
    /// for <see cref="Songhay.Data.ICommandHandler"/>.
    /// </summary>
    public class DataCommandInput
    {
        /// <summary>
        /// Default constructor.
        /// </summary>
        public DataCommandInput() { }

        /// <summary>
        /// Constructs with the specified command name
        /// and <see cref="System.Data.Common.DbConnection"/>.
        /// </summary>
        /// <param name="commandName">the command name</param>
        /// <param name="dataConnection">the <see cref="System.Data.Common.DbConnection"/></param>
        public DataCommandInput(string commandName, DbConnection dataConnection)
        {
            this._commandName = commandName;
            this._dataConnection = dataConnection;
        }

        /// <summary>
        /// The defined name of the command.
        /// </summary>
        public string CommandName
        {
            get { return this._commandName; }
            set { this._commandName = value; }
        }

        /// <summary>
        /// The connection to the DBMS.
        /// </summary>
        public DbConnection DataConnection
        {
            get { return this._dataConnection; }
            set { this._dataConnection = value; }
        }

        /// <summary>
        /// Converts and incoming command name into one element of a strongly-typed enumeration.
        /// </summary>
        /// <typeparam name="EnumerationType">The <see cref="System.Type"/> of the enumeration, usually called <c>DataCommand</c>.</typeparam>
        /// <param name="commandName">The incoming command name.</param>
        /// <returns>Returns one element of the specified enumeration or the default value of the enumeration, usually <c>DataCommand.Undefined</c>.</returns>
        public static EnumerationType GetDataCommand<EnumerationType>(string commandName)
        {
            if(!string.IsNullOrEmpty(commandName)
                && System.Enum.IsDefined(typeof(EnumerationType), commandName))
            {
                return (EnumerationType)System.Enum.Parse(typeof(EnumerationType), commandName, true);

            }
            else
            {
                return default(EnumerationType);
            }
        }

        /// <summary>
        /// The conventional message to return when the implementor produces a <c>null</c> response.
        /// </summary>
        /// <returns>Returns message document.</returns>
        public static XPathDocument GetInputNotHandledMessage()
        {
            return XmlUtility.GetInternalMessageDocument("Input Not Handled", null);
        }

        /// <summary>
        /// The conventional message to return when the implementor has not implemented a command.
        /// </summary>
        /// <param name="commandName">The name of the current data command, usually <see cref="DataCommandInput.CommandName"/></param>
        /// <returns>Returns message document.</returns>
        public static XPathDocument GetNotImplementedMessage(string commandName)
        {
            string[] sa = new string[]
            {
                "The input data command is not yet implemented.",
                string.Format("incomingMessage: {0}", commandName)
            };
            return XmlUtility.GetInternalMessageDocument("Data Command Not Implemented", sa);
        }

        /// <summary>
        /// The conventional message to return when the implementor cannot define the data command.
        /// </summary>
        /// <param name="commandName">The name of the current data command, usually <see cref="DataCommandInput.CommandName"/></param>
        /// <returns>Returns message document.</returns>
        /// <remarks>This method is usually called when the enumeration of data commands equals <c>Undefined</c>.</remarks>
        public static XPathDocument GetUndefinedCommandMessage(string commandName)
        {
            string[] sa = new string[]
            {
                "The input is an undefined data command.",
                string.Format("incomingMessage: {0}", commandName)
            };
            return XmlUtility.GetInternalMessageDocument("Unknown Data Command", sa);
        }

        private string _commandName;
        private DbConnection _dataConnection;
    }
}
